iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
Kubernetes

不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA系列 第 17

Day 17|Affinity 與 Anti-Affinity:不只是「能不能排」,還要考慮「排得好不好」

  • 分享至 

  • xImage
  •  

今天先複習一下,昨天學的 nodeSelector
他的概念很簡單

假設:

disktype=ssd

Pod 指定:

nodeSelector:
  disktype: ssd

代表:

只有符合 disktype=ssd 的 Node 才能跑這個 Pod。

但 Production 常常不是只有「可以」和「不可以」。

例如:

API 最好跑 SSD,但 SSD 不夠時,其他 Node 也可以。

或者:

3 個 API Pod 不要全部塞在同一台 Node。

這時就需要:

Node Affinity
Pod Affinity / Anti-Affinity
Topology Spread Constraints

Node Affinity:nodeSelector 的進階版

Node Affinity 可以理解成:

Pod 對 Node 提出更彈性的排程條件。

例如:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
        - matchExpressions:
            - key: disktype
              operator: In
              values:
                - ssd
                - nvme

意思是:

Pod 只能排到 disktype=ssddisktype=nvme 的 Node。

nodeSelector 相比,Node Affinity 可以使用:

In
NotIn
Exists
DoesNotExist
Gt
Lt

所以它能表達更複雜的條件。


Required 和 Preferred

Node Affinity 最重要的是分清楚這兩種規則。

required

代表:

一定要符合。

如果要求:

disktype=nvme

但 Cluster 沒有任何 NVMe Node,Pod 就會:

Pending

另一種是:

preferred

代表:

最好符合,但不是強制。

例如:

preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 100
    preference:
      matchExpressions:
        - key: disktype
          operator: In
          values:
            - ssd

意思是:

Scheduler 會優先選 SSD Node,但沒有 SSD 時還是可以選其他 Node。

所以記住:

required = 一定要
preferred = 最好有

那個超長名字是什麼?

requiredDuringSchedulingIgnoredDuringExecution

其實拆開就很好懂。

required

代表一定要符合。

DuringScheduling

代表排程時檢查。

IgnoredDuringExecution

代表 Pod 跑起來之後,即使 Node Label 後來改掉,也不會因此自動把 Pod 趕走。

所以整句就是:

排程時一定要符合,但執行後條件改變,不會自動驅逐 Pod。


Pod Anti-Affinity:不要全部擠在一起

假設:

API replicas = 3

Scheduler 可能排成:

worker1
├── api-1
├── api-2
└── api-3

技術上沒有錯,但只要 worker1 掛掉:

3 個 API 一起消失

所以我們通常希望:

worker1 → api-1
worker2 → api-2
worker3 → api-3

這時可以使用:

Pod Anti-Affinity

例如:

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values:
                  - api
          topologyKey: kubernetes.io/hostname

這段的意思是:

如果某台 Node 已經有 app=api 的 Pod,新 API Pod 就盡量不要再放同一台。


topologyKey 是什麼?

這裡:

kubernetes.io/hostname

代表:

以 Node 為分散單位。

所以:

同 hostname
=同一台 Node

如果改成:

topology.kubernetes.io/zone

就代表:

以 Availability Zone 為分散單位。

例如:

Zone A → API
Zone B → API
Zone C → API

這可以降低單一 Node 或單一 Zone 故障時的影響。


Affinity 和 Anti-Affinity

兩個概念很好記。

Affinity:

我希望跟誰靠近。

Anti-Affinity:

我希望跟誰分開。

例如 Worker 跟 Redis 如果需要低延遲,可以考慮:

Pod Affinity

API replicas 為了避免全部集中在同一台 Node,可以使用:

Pod Anti-Affinity

Topology Spread Constraints:讓 Pod 分布更平均

如果你的需求不是「完全分開」,而是:

希望 Pod 在不同 Node 上分得平均一點。

就可以使用:

topologySpreadConstraints

例如:

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: kubernetes.io/hostname
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app: api

maxSkew: 1 可以簡單理解成:

不同 Node 上的 API Pod 數量,差距不要太大。

例如:

worker1 = 2
worker2 = 1

可以。

但:

worker1 = 3
worker2 = 0

就比較不平均。

而:

ScheduleAnyway

代表:

即使無法完全平均,Pod 還是可以排程。

所以 Topology Spread 關心的是:

整體 Pod 分布是否平均。

Pod Anti-Affinity 則比較像:

某些 Pod 不要靠太近。


Production Scheduling 在想什麼?

現在可以發現,Kubernetes Scheduling 不只是:

找一台 Node 把 Pod 塞進去

而是在平衡:

Resource
Performance
Availability
Failure Domain
Business Requirement

例如:

這台 Node CPU 夠不夠?
是不是 SSD?
Replica 有沒有全部擠在一起?
是不是全部都在同一個 Zone?

所以 Scheduling 真正做的是:

先找出可以跑 Pod 的 Node,再從中選出比較適合的 Node。


今天的故障實驗

故意設定:

required
disktype=nvme

但 Cluster 裡沒有任何:

disktype=nvme

重新 Deploy 後,你會看到:

Pod → Pending

這時不要急著刪 Pod。

執行:

kubectl describe pod POD_NAME -n cka-lab

查看:

Events

可能會看到:

node(s) didn't match Pod's node affinity/selector

意思就是:

Scheduler 找不到符合條件的 Node。

這是很典型的 CKA Scheduling 排錯題。


Day 17 小結

今天的 Scheduling 可以整理成:

Node 條件
│
├── nodeSelector
└── Node Affinity

Pod 與 Pod
│
├── Pod Affinity
└── Pod Anti-Affinity

Pod 整體分布
│
└── Topology Spread Constraints

最重要的差異就是:

Node Affinity
=Pod 想去哪種 Node

Pod Affinity
=Pod 想跟誰靠近

Pod Anti-Affinity
=Pod 想跟誰分開

Topology Spread
=Pod 要怎麼分得比較平均

昨天學的是:

能不能去?

今天開始學的是:

去哪裡比較好?

下一篇會進入:

cordon
drain
uncordon
PodDisruptionBudget

也就是:

如果 Node 要停機維修,要怎麼安全地把它下線?


上一篇
Day 16|Scheduler 到底怎麼選 Node?nodeSelector、Taint 與 Toleration 一次搞懂
下一篇
Day 18|Node 要維修怎麼辦?cordon、drain、uncordon 與 PDB 實戰
系列文
不是背 YAML!30 天從零打造 Kubernetes 微服務:從本機實戰一路到 CKA18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言